package com.yuxl.admin.common.socket.utils;

import com.alibaba.fastjson2.JSONObject;
import com.yuxl.admin.common.socket.domain.SocketInMessage;
import com.yuxl.admin.common.socket.service.WebSocketService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Objects;

@Slf4j
@Component
@RequiredArgsConstructor
public class SocketMessageUtil {

    private final WebSocketService webSocketService;

    /**
     * 向所有连接的用户发送消息
     * @param message 消息
     * @return 发送操作完成的Mono
     */
    public Mono<Void> sendMessageToAllUsers(SocketInMessage message) {
        log.debug("正在向所有客户端发送消息: {}", JSONObject.toJSONString(message));
        return Flux.fromIterable(webSocketService.getAllSessions().entrySet())
                .flatMap(entry -> {
                    String username = entry.getKey();
                    List<WebSocketSession> sessions = entry.getValue().stream().filter(Objects::nonNull).toList();
                    return Flux.fromIterable(sessions)
                            .flatMap(session -> webSocketService.isUserLoggedIn(session)
                                    .flatMap(isLoggedIn -> {
                                        if (isLoggedIn && session.isOpen()) {
                                            // 发送消息到会话
                                            return session.send(Mono.just(session.textMessage(JSONObject.toJSONString(message))))
                                                    .doOnSuccess(v -> log.debug("消息成功发送给用户: {}", username))
                                                    .onErrorResume(e -> {
                                                        log.error("发送消息给用户 {} 失败", username, e);
                                                        return Mono.empty();
                                                    });
                                        } else {
                                            log.debug("用户 {} 未登录或连接已关闭，断开连接", username);
                                            return closeSession(session);
                                        }
                                    }));
                })
                .then();
    }

    /**
     * 向指定用户发送消息
     * @param message 消息
     * @return 发送是否成功的Mono<Boolean>
     */
    public Mono<Boolean> sendMessageToUser(SocketInMessage message) {
        log.debug("尝试向用户 {} 发送消息: {}", message.getTo(), message.getMessage());
        return Flux.fromIterable(webSocketService.getSessions(message.getTo()))
                .flatMap(session -> webSocketService.isUserLoggedIn(session)
                        .flatMap(isLoggedIn -> {
                            if (isLoggedIn && session.isOpen()) {
                                // 发送消息到会话
                                message.setTo(null);
                                return session.send(Mono.just(session.textMessage(JSONObject.toJSONString(message))))
                                        .thenReturn(true);
                            } else {
                                log.debug("用户 {} 未登录或连接已关闭，断开连接", message.getTo());
                                return closeSession(session).thenReturn(false);
                            }
                        }))
                .reduce(Boolean::logicalOr)
                .defaultIfEmpty(false);
    }

    /**
     * 向指定会话发送消息
     * @param session 目标WebSocket会话
     * @param message 要发送的消息
     * @return 发送操作完成的Mono
     */
    public Mono<Void> sendMessageToSession(WebSocketSession session, String message) {
        String username = webSocketService.getUsername(session);
        return webSocketService.isUserLoggedIn(session)
                .flatMap(isLoggedIn -> {
                    if (isLoggedIn && session.isOpen()) {
                        // 发送消息到会话
                        return session.send(Mono.just(session.textMessage(message)))
                                .doOnSuccess(v -> log.debug("消息成功发送给用户: {}", username))
                                .onErrorResume(e -> {
                                    log.error("发送消息给用户 {} 失败", username, e);
                                    return Mono.empty();
                                });
                    } else {
                        log.debug("用户 {} 未登录或连接已关闭，断开连接", username);
                        return closeSession(session);
                    }
                });
    }

    /**
     * 关闭WebSocket会话
     * @param session 要关闭的WebSocket会话
     * @return 关闭操作完成的Mono
     */
    private Mono<Void> closeSession(WebSocketSession session) {
        String username = webSocketService.getUsername(session);
        // 从WebSocketService中移除会话
        webSocketService.removeSession(username, session);
        // 关闭会话
        return session.close();
    }
}
